import { Injectable, Inject } from '@angular/core';
import { Headers } from "@angular/http";
import { CmHttp } from "CmHttp";
import { BehaviorSubject } from "rxjs/BehaviorSubject";
import { Subject } from "rxjs/Subject";
import { ReplaySubject } from "rxjs/ReplaySubject";
import { Observable } from "rxjs/Observable";
import { WatchlistGroup, symbolType } from "./watchlist-mini.model";
import { SocketService } from "socket";
import { UserService } from "user";
import { SummaryNameService, SearchStockClass, BASEURL, USERURL, STOCKURL } from "shared";
import { sortFn } from "./../quote/quote-table/utils";
import * as _ from "lodash";
import { group } from '@angular/animations/src/animation_metadata';

const getParams = symbols => {
  return symbols.reduce((str, symbol) => `${str}symbol=${symbol}&`, "?");
};

@Injectable()
export class WatchlistMiniService {
  private api_url = `${USERURL}/api/v2/sc/stocks/my`;
  private userId: string;
  // private _groups: BehaviorSubject<WatchlistGroup[]>;
  private _groups: BehaviorSubject<any>;
  private dataStore: {
    groups: WatchlistGroup[]
  };
  stockSub: Subject<any> = new Subject<any>();
  // stockSubscription;
  rawGroups: WatchlistGroup[];  // : Observable<WatchlistGroup[]>;
  rawGroupsLength: number;
  // 用于给分组数据显示推送数据
  rawGroupsSub = new ReplaySubject(1);
  rawGroupsLengthSub: Subject<number> = new Subject();
  rawGroupWithIntervalSub = new Subject();
  // 历史浏览自选股
  historyGroup: symbolType[];
  historyGroupsSub = new ReplaySubject(1);
  historyGroupWithIntervalSub = new Subject();

  initStockSub = new Subject();
  // 创建新分组提示
  emptyGroupSub = new Subject();
  emptyGroupOfAddStockSub = new Subject();
  emptyOfSelectStockSub = new Subject();

  addStockSub = new Subject();

  isAddStock = false;
  // [全部自选股]
  // fullGroups: WatchlistGroup = {
  //   id: "",
  //   name: "全部自选股",
  //   symbols: [],
  //   order: "0",
  //   details: [],
  //   isShow: true
  // };
  options = {
    sortBy: "",
    isReversed: false
  };
  lastSortGroupId: string;
  originData;
  sortedData;
  isUserLogedin: boolean;

  // 为未登录用户展示的自选股列表
  DEFAULTSYMBOLS = ["000001.SS", "000002.SS", "000003.SS"];
  // for varify latest stock
  localDB: Array<SearchStockClass> = [];
  
  appAgent: string;
  headers = new Headers();
  
  initStockStatus: boolean = false;

  constructor(
    private http: CmHttp,
    private socket: SocketService,
    private userService: UserService,
    private sns: SummaryNameService) {
    this.dataStore = { groups: [] };
    this._groups = new BehaviorSubject<any>([]);

    sns.summaryNameSub.subscribe((res: Array<SearchStockClass>) => {
      this.localDB = res;
      // console.debug('%c LocalDB: ', 'color:#F09', this.localDB);
    });

    // 按照分组的数据map每组个股的数据
    this._groups.subscribe(res => {
      // 空数据跳过
      if (!res || !res.length) {
        this.rawGroupsSub.next([...res]);
        this.rawGroups = [...res];
        return false;
      }
      // console.debug("groups subscription: ", res);
      res.map(singleGroup => {
        Observable.of(singleGroup).flatMap(res => {
          // console.debug("singleGroup: ", res);
          let param = getParams(res["symbols"]);
          let symbolsString = (param && res["symbols"].length) ? param : "";
          // console.debug("singleGroup query string: ", symbolsString);
          return this.http.get(`${STOCKURL}/api/v2/sc/stocks/quotation${symbolsString}`, {});
            .map(res => {
              if (res.isError || !res.data)
                 return;
              let data = res.data;
              // format STOPT stock data to '--'
              data = data.map(row => {
                if (row.status && (row.status === "STOPT" || row.status === "SUSP")) {
                  row.current = "--";
                  row.change_rate = "--";
                  row.change_amount = "--";
                }
                return row;
              });
              singleGroup["details"] = data;
              return data;  // Observable.of(res);
              // console.debug("singleGroup renew: ", singleGroup);
            });
        })
          .subscribe(data => {
            data ? this.stockSub.next(data) : "";
          }, err => {
            // console.debug("watchlist quotation request err: ", err.json());
            return singleGroup;
          });
      });
      this.rawGroups = [...res];
      this.rawGroupsSub.next(this.rawGroups);
      this.rawGroupsLengthSub.next(this.rawGroups.length);
      // console.debug("rawGroups: ", this.rawGroups);

      // subscribe update
      this.rawGroups.map(g => {
        let symbols = [];
         g.stocks.forEach(stock => {
           symbols.push(stock['symbol'])
        });
        if (symbols.length > 0) {
          this.socket.emit('sub', { channel: 'watchlist', symbols: symbols });
        }
        g.isShow = (g.isShow === undefined) ? true : g.isShow;
      });
    });

    // 分组个数订阅
    this.rawGroupsLengthSub.subscribe(len => {
      this.rawGroupsLength = len;
    });

    // 定时更新自选股分组数据
    // this.rawGroupWithIntervalSub.subscribe((data: WatchlistGroup[]) => {
    //   this.rawGroupsSub.next(data);
    //   this.rawGroupsLengthSub.next(data.length);
    // });
    // this.historyGroupWithIntervalSub.subscribe((data: WatchlistGroup[]) => {
    //   this.historyGroupsSub.next(data);
    // });
    // Observable.zip(
    //   this.rawGroupWithIntervalSub,
    //   Observable.interval(5000),
    //   ((data: WatchlistGroup[]), count) => Observable.of(data)
    // ).subscribe((data: WatchlistGroup[]) => {
    //   this.rawGroupsSub.next(data);
    //   this.rawGroupsLengthSub.next(data.length);
    // });

    // Observable.zip(
    //   this.historyGroupWithIntervalSub,
    //   Observable.interval(5000),
    //   ((data: WatchlistGroup[]), count) => Observable.of(data)
    // ).subscribe((data: WatchlistGroup[]) => {
    //   this.historyGroupsSub.next(data);
    // });

    // 加载历史浏览的自选股detail数据
    this.loadHistoryDetails();

    // 合并到全部自选股
    // this.stockSubscription = this.stockSub
    //   .subscribe(list => {
    //     // console.debug("list: ", list);
    //     // remove repeat
    //     let tmpList = list.filter(res => {
    //       let tmpValue = true;
    //       this.fullGroups.details.forEach(singleS => {
    //         if (singleS['symbol'] === res.symbol) {
    //           tmpValue = false;
    //           return false;
    //         }
    //       });
    //       return tmpValue;
    //     });

    //     // append stock details
    //     let tempDetailsArr = [...this.fullGroups.details, ...tmpList];
    //     this.fullGroups["details"] = Array.from(new Set(tempDetailsArr));
    //   });

    // handle update
    this.socket.on("watchlist", data => {
      // console.debug("socket data: ", data);

      let watchlistData = data; //adapt to v2 api
      //let watchlistData = Object.keys(data).map(key => data[key]).reduce(first => first);

      // 全部自选股的更新
      // this.fullGroups["details"] = this.fullGroups["details"].map(row => {
      //   if (row['symbol'] === watchlistData['symbol']) {
      //     row = _.merge({}, row, watchlistData);
      //     // console.debug("socket update row: ", row);
      //   }
      //   return row;
      // });

      // (登录用户进行)自选股分组的更新
      if (this.isUserLogedin && this.rawGroups && this.rawGroups.length) {
        this.rawGroups = this.rawGroups.map(singleG => {
          if (!singleG.stocks) return singleG;
          singleG.stocks = singleG.stocks.map(row => {
            if (row['symbol'] === watchlistData['symbol']) {
              row = _.merge({}, row, watchlistData);
              // console.debug("socket update row: ", row);
              if (row["status"] && (row["status"] === "STOPT" || row["status"] === "SUSP")) {
                row["current"] = "--";
                row["change_rate"] = "--";
                row["change_amount"] = "--";
              }
            }
            return row;
          });
          return singleG;
        });

        // this.rawGroupWithIntervalSub.next(this.rawGroups);
        this.rawGroupsSub.next(this.rawGroups);
        this.rawGroupsLengthSub.next(this.rawGroups.length);
      }

      // 历史浏览自选股分组的更新
      if (this.historyGroup) {
        this.historyGroup = this.historyGroup.map(row => {
          if (row['symbol'] === watchlistData['symbol']) {
            row = _.merge({}, row, watchlistData);
            // console.debug("socket update row: ", row);
            if (row["status"] && (row["status"] === "STOPT" || row["status"] === "SUSP")) {
              row["current"] = "--";
              row["change_rate"] = "--";
              row["change_amount"] = "--";
            }
          }
          return row;
        });
        // this.historyGroupWithIntervalSub.next(this.historyGroup);
        this.historyGroupsSub.next(this.historyGroup);
      }
    });

    // let elec  = require('electron');
    // if (elec && elec.remote) {
    //   this.appAgent = elec.remote.getGlobal("appAgent");
    // }
    // this.headers.append("User-Agent",this.appAgent);
  }

  // 加载历史浏览的股票详情
  loadHistoryDetails() {
    this.allHistoryStocks = this.getHistorySymbols();
    let symbolsString = (this.allHistoryStocks.length) ? getParams(this.allHistoryStocks) : "";

    // console.debug("loadHistoryDetails: ", this.allHistoryStocks, symbolsString);
    this.http.get(`${STOCKURL}/api/v2/sc/stocks/quotation${symbolsString}`, {})
      .subscribe(res => {
        if (res.isError || !res.data)
           return;
        let data = res.data;
        // format STOPT stock data to '--'
        data = data.map(row => {
          if (row.status && (row.status === "STOPT" || row.status === "SUSP")) {
            row.current = "--";
            row.change_rate = "--";
            row.change_amount = "--";
          }
          return row;
        });
        this.historyGroup = this.disposalData(this.allHistoryStocks, data);;
        this.historyGroupsSub.next(this.historyGroup);
        if (this.initStockStatus) {
          this.initStockSub.next(this.historyGroup);
        }
        // console.debug("history group load: ", this.historyGroup);
      });

    // subscribe update
    this.socket.emit('sub', { channel: 'watchlist', symbols: this.allHistoryStocks });
  }
  
  /**
   * 整理历史记录数组数据（顺序）
   */
  private disposalData(allHistoryStocks: any[], data: symbolType[]) {
    let result: symbolType[] = data;
    let counterpart: symbolType[] = data.map(x => Object.assign({}, x));
    for(let i = 0 ; i < allHistoryStocks.length;  i++ ) {
      result[i] = this.getsymbolType(allHistoryStocks[i], counterpart);
      let index = counterpart.indexOf(result[i]);
      if (index > -1) {
        counterpart.splice(index, 1);
      }
    }
    return result;
  }

  private getsymbolType(symbol: string, data: symbolType[]) {
    for( let i = 0 ; i < data.length ; i ++ ) {
      if( data[i].symbol === symbol ) {
        return data[i];
      }
    }
  }

  /**
   * 按照登录状态加在自选股分组列表的内容显示
   * @param status 登录状态
   */
  loadWatchlistData(status: boolean) {
    if (status) {
      if (this.rawGroupsLength) return;
      this.getGroups();
    } else {
      // load default fullGroup data
      this.loadDefaultData();
    }
  }

  // 未登录用户加载默认的全部自选股分组
  loadDefaultData() {
    this.isUserLogedin = false;
    // add symbols
    // this.fullGroups.symbols = this.DEFAULTSYMBOLS;
    let param = getParams(this.DEFAULTSYMBOLS);
    // console.debug("loadDefaultData query string: ", param);
    this.http.get(`${STOCKURL}/api/v2/sc/stocks/quotation${param}`, {})
      .subscribe(res => {
        // console.debug("loadDefaultData stock data: ", res);
        // this.fullGroups["details"] = res.data;
        // subscribe default symbols
        this.socket.emit('sub', { channel: 'watchlist', symbols: this.DEFAULTSYMBOLS });
      });
  }

  setOrder(sortBy: string, groupId: string) {
    // update sort options
    // console.log('sort options:', this.options);
    if (this.lastSortGroupId === groupId) {
      this.options = _.merge({}, this.options, {
        sortBy: sortBy,
        isReversed: this.options.sortBy === sortBy ? !this.options.isReversed : this.options.isReversed
      });
    } else {
      this.options = _.merge({}, this.options, { sortBy: sortBy });
      this.lastSortGroupId = groupId;
    }
    // console.log('sort options update:', this.options);

    if (!sortBy) return;
    if (groupId) {
      // rawGroups
      this.rawGroups = this.rawGroups.map(singleG => {
        if (singleG.groupId === groupId) {
          let data = this.sortData(singleG.stocks);
          // format STOPT stock data to '--'
          data = data.map(row => {
            if (row.status && (row.status === "STOPT" || row.status === "SUSP")) {
              row.current = "--";
              row.change_rate = "--";
              row.change_amount = "--";
            }
            return row;
          });
          singleG.stocks = data;
          return singleG;
        } else {
          return singleG;
        }
      });

      this.rawGroupsSub.next(this.rawGroups);
      this.rawGroupsLengthSub.next(this.rawGroups.length);
    } else {
      // fullGroup
      // this.fullGroups.details = this.sortData(this.fullGroups.details);
    }
  }

  private sortData(dataArray: Object[]) {
    this.originData = [...dataArray];
    this.sortedData = this.originData.sort(sortFn(this.options.sortBy, this.options.isReversed));
    return [...this.sortedData];
  }

  // get groups() {
  //   // return this._groups.asObservable();
  //   return Observable.of(this.fullGroups);
  // }

  // resetFullGroups() {
  //   // unsubscribe update
  //   if (this.rawGroups) {
  //     this.rawGroups.forEach(g => {
  //       this.socket.emit('unsub', { channel: 'watchlist', symbols: g.symbols });
  //     });
  //   } else {
  //     // 未登录用户退订推送
  //     this.socket.emit('unsub', { channel: 'watchlist', symbols: this.DEFAULTSYMBOLS });
  //   }
  //   this.fullGroups["details"] = [];
  // }

  private findIndex(group: WatchlistGroup) {
    let idx = undefined;
    this.dataStore.groups.map((a, i) => {
      if (a.groupId === group.groupId) {
        idx = i;
      }
    });
    return idx;
  }

  // 针对自选股分组的CURD操作

  // POST 
  addGroup(name: string, symbols: string[]) {
    this.http.post(this.api_url + "/groups/add", { name, symbols }, { headers: this.headers, withCredentials: true })
      .catch(error => {
        this.alertMessage();
        console.info("add group:", error);
        return Observable.throw(error);
      })
      .subscribe(data => {
        if ( data.code === 0  ) {
          const group:WatchlistGroup = data.data;
          this.dataStore.groups = [...this.dataStore.groups, group];
          this._groups.next(Object.assign({}, this.dataStore).groups); 
          if( this.isAddStock && this.isEmptyGroupOfAddStock()) {
            this.emptyGroupOfAddStockSub.next();
          }    
        } else if(data.code === 401) {
          this.userService.updateLogStatus(false);
          this.userService.setModal("login");
        }
      });
  }

  // DELETE /watchlists/:id
  deleteGroup(group: WatchlistGroup) {
    const url = `${this.api_url}/groups/remove`;
    const index = this.findIndex(group);
    this.http.post(url, { "groupId": group.groupId }, { headers: this.headers, withCredentials: true })
      .subscribe(data => {
        if ( data.code === 0 ) {
          this.dataStore.groups = [
            ...this.dataStore.groups.slice(0, index),
            ...this.dataStore.groups.slice(index + 1)
          ];
          this._groups.next(Object.assign({}, this.dataStore).groups);
          console.debug("delete group success:", _);
        } else if(data.code === 401) {
          this.userService.updateLogStatus(false);
          this.userService.setModal("login");
        }
      }, err => {
        this.alertMessage();
        console.warn("delete group err:", err);
      });
  }

  // GET /watchlists
  getGroups() {
    this.isUserLogedin = true;
    this.http.get(this.api_url + "/groups", { headers: this.headers, withCredentials: true })
      .catch(error => {
        this.alertMessage();
        console.info("get get groups:", error);
        return Observable.throw(error);
      })
      // .do(t => console.log("my watchlist groups: ", t))
      .subscribe(data => {
        if ( data.code === 0 ) {
          const groups:WatchlistGroup[] = data.data;
          for ( let i = 0 ; i < groups.length ; i ++ ) {
            groups[i].isShow = true;
          }
          this.updateFullStoreAndSubject(groups);
        } else if(data.code === 401) {
          this.userService.updateLogStatus(false);
          this.userService.setModal("login");
        }
      });
  }

  // PATCH /watchlist/:id/name
  updateGroupName(group: WatchlistGroup, name: string) {
    // const url = `${this.api_url}/${group.groupId}/name`;
    // const index = this.findIndex(group);
    // let updatedGroup = Object.assign({}, group, { name: name });
    // this.http.patch(url, { name: name }, { headers: this.headers, withCredentials: true })
    //   .subscribe(res => {
    //     console.debug("update group name:", res);
    //     this.updatePartStoreAndSubject(updatedGroup, index);
    //   }, err => {
    //     console.warn("update group name err:", err);
    //   });
  }

  // PATCH /watchlist/:id/order  // top,up,down
  updateGroupOrder(group: WatchlistGroup, direction: string) {
    // const url = `${this.api_url}/${group.groupId}/order`;
    // const index = this.findIndex(group);
    // this.http.patch(url, { direction: direction }, { headers: this.headers, withCredentials: true })
    //   .subscribe(data => {
    //     console.debug("update group order:", data);
    //     this.updateFullStoreAndSubject(data);
    //   }, err => {
    //     console.warn("update group order err:", err);
    //   });
  }


  // 针对分组内部的个股symbol进行CUD操作

  // POST
  addGroupSymbols(group: WatchlistGroup, symbols: string[]) {
    this.socket.emit('sub', { channel: 'watchlist', symbols: symbols });

    const url = `${this.api_url}/group/addStock`;
    const index = this.findIndex(group);
    // console.debug("addGroupSymbols:", symbols, url, index, group);
    this.http.post(url, { "groupId": group.groupId, symbols: symbols }, { headers: this.headers, withCredentials: true })
      .subscribe(data => {
        console.debug("add group symbols data:", data);
        if ( data.code === 0 ) {
          const symbol:symbolType[] = data.data;
          if (symbol.length > 0) {
            let newGroup = Object.assign({}, group);
            for ( let i = 0 ; i < symbol.length ; i ++ ) {
              newGroup.stocks.push(symbol[i]);
            }
            this.updatePartStoreAndSubject(newGroup, index);
          }
        } else if(data.code === 401) {
          this.userService.updateLogStatus(false);
          this.userService.setModal("login");
        }
      }, err => {
        this.alertMessage();
        console.warn("add group symbols err:", err);
      });
  }

  // DELETE /watchlist/:id/symbols
  deleteGroupSymbols(group: WatchlistGroup, symbols: string[]) {
    this.socket.emit('unsub', { channel: 'watchlist', symbols: symbols });

    const url = `${this.api_url}/group/removeStock`;
    const index = this.findIndex(group);
    // console.debug("deleteGroupSymbols:", symbols, url, index, group);
    this.http.post(url, { "groupId": group.groupId, symbols: symbols }, { headers: this.headers, withCredentials: true })
      .subscribe(data => {
        if ( data.code === 0 ) {
            let newGroup = Object.assign({}, group);
            // newGroup.symbols.filter(x => x !== data["symbols"]);
            for ( let i = 0 ; i < group.stocks.length ; i ++ ) {
              if ( group.stocks[i].symbol === symbols[0] ) {
                group.stocks.splice(i, 1);
              }
            }
            this.updatePartStoreAndSubject(newGroup, index);
        } else if(data.code === 401) {
          this.userService.updateLogStatus(false);
          this.userService.setModal("login");
        }
      }, err => {
        this.alertMessage();
        console.warn("delete group stock err:", err);
      });
  }

  // PATCH /watchlist/:id/symbols/:symbol
  setTopGroupSymbol(group: WatchlistGroup, symbol: string) {
    const url = `${this.api_url}/${group.groupId}/symbols/${symbol}`;
    const index = this.findIndex(group);
    this.http.patch(url, {}, { headers: this.headers, withCredentials: true })
      .subscribe(data => {
        if (data["symbols"]) {
          let newGroup = Object.assign({}, group);
          // let tempArr = newGroup.symbols.filter(x => x !== data["symbols"]);
          // newGroup.symbols = [data["symbols"], ...tempArr];
          newGroup.stocks = data["stocks"];
          this.updatePartStoreAndSubject(newGroup, index);
        }
      });
  }

  /**
   * 更新全部的分组
   */
  private updateFullStoreAndSubject(groups) {
    this.dataStore.groups = [...groups];
    this._groups.next([...groups]);
    // this._groups.next(Object.assign({}, this.dataStore).groups);
  }

  /**
   * 更新某一个分组的内容
   */
  private updatePartStoreAndSubject(group, index) {
    // console.log("update part store:", group);
    let len = this.dataStore.groups.length;
    // console.log("index, len:", index, len);
    // is the last group
    if (index !== -1) {
      this.dataStore.groups = [
        ...this.dataStore.groups.slice(0, index),
        group,
        ...this.dataStore.groups.slice(index + 1)
      ];
    } else {
      this.dataStore.groups = [...this.dataStore.groups.slice(0, index), group];
    }

    this._groups.next(Object.assign({}, this.dataStore).groups);
    // console.log("update part store this.dataStore:", this.dataStore.groups);
  }

  // 最近浏览的自选股部分
  // 最大历史记录数
  MAX_HISTORY_LEN = 18;
  // 最近浏览历史在localStorage中的key
  STOCK_HISTORY_KEY = 'historySymbols';
  allHistoryStocks = [];
  /**
   * 动态更新最近浏览的个股的历史记录
   * @param {String} symbol 股票代码
   */
  updateHistorySymbols(symbol: string) {
    if (!symbol) {
      return;
    }

    // 检查股票代码的真实性
    let results = [];
    this.localDB.forEach((v, i) => {
      try {
        if (v.symbol.indexOf(symbol) >= 0) {
          results.push(v);
        }
      } catch (e) {
        console.error('unvalid symbol:', e);
      }
    });
    if (!results.length) {
      return;
    }

    // 是否已存在于历史记录中
    let symbols = this.getHistorySymbols();
    let index = symbols.indexOf(symbol);

    if (index === -1) { // 未浏览过的个股直接加到数组开头
      symbols.unshift(symbol);
      // 若超过历史记录数限制则从数组结尾删除
      if (symbols.length > this.MAX_HISTORY_LEN) {
        symbols.pop();
      }
    } else { // 已浏览过的个股移动到数组开头
      let removedItems = symbols.splice(index, 1);
      symbols.unshift(removedItems[0]);
    }

    window.localStorage.setItem(this.STOCK_HISTORY_KEY, symbols.join(','));
    // this.allHistoryStocks = symbols;
    if (index === -1) {
      this.loadHistoryDetails();
    }
  };

  /**
   * 读取最近浏览的个股历史记录
   */
  getHistorySymbols() {
    let item = window.localStorage.getItem(this.STOCK_HISTORY_KEY);
    if ( item ) {
      return item.split(',')
    } else {
      return ["000001.SS"];
    }
  };

  private alertMessage() {
    alert("服务连接超时，请稍后重试！");
  }

  private isEmptyGroupOfAddStock() {
    return this.dataStore.groups.length === 1;
  }
}